#include "pch.h"

#include "math/directx/dxfloat4.h"
#include "core/config.h"


#ifdef RE_USE_DX


namespace Math
{

	///
	float4::float4()
	{

	}


	///
	float4::float4(scalar x, scalar y, scalar z, scalar w)
	{
		this->m_vec = XMVectorSet(x,y,z,w);
	}


	///
	float4::float4(XMVECTOR rhs):
	m_vec(rhs)
	{

	}





	///
	void float4::operator = (const float4 & rhs)
	{
		this->m_vec = rhs.m_vec;
	}


	///
	void float4::operator =(XMVECTOR rhs)
	{
		this->m_vec = rhs;
	}


	///
	bool float4::operator == (const float4 & rhs) const 
	{
		return (0 != XMVector4Equal(this->m_vec, rhs.m_vec));
	}


	///
	bool float4::operator != (const float4 & rhs) const 
	{
		return (0 != XMVector4NotEqual(this->m_vec, rhs.m_vec));
	}


	///
	void float4::operator += (const float4 & rhs)
	{
		this->m_vec = XMVectorAdd(this->m_vec, rhs.m_vec);
	}


	///
	void float4::operator -= (const float4 & rhs) 
	{
		this->m_vec = XMVectorSubtract(this->m_vec, rhs.m_vec);
	}


	///
	void float4::operator *= (scalar s)
	{
		this->m_vec = XMVectorScale(this->m_vec, s);
	}


	///
	float4 float4::operator - () const 
	{
		return XMVectorNegate(this->m_vec);
	}


	///
	float4 float4::operator + (const float4 & rhs) const
	{
		return XMVectorAdd(this->m_vec, rhs.m_vec);
	}


	///
	float4 float4::operator - (const float4 & rhs) const 
	{
		return XMVectorSubtract(this->m_vec, rhs.m_vec);
	}


	///
	float4 float4::operator *(scalar s) const 
	{
		return XMVectorScale(this->m_vec, s);
	}





	///
	void float4::set(scalar x, scalar y, scalar z, scalar w)
	{
		this->m_vec = XMVectorSet(x, y, z, w);
	}


	///
	void float4::setx(scalar x)
	{
		this->m_vec = XMVectorSetXPtr(this->m_vec, &x);
	}


	///
	void float4::sety(scalar y)
	{
		this->m_vec = XMVectorSetYPtr(this->m_vec, &y);
	}


	///
	void float4::setz(scalar z)
	{
		this->m_vec = XMVectorSetZPtr(this->m_vec, &z);
	}


	///
	void float4::setw(scalar w)
	{
		this->m_vec = XMVectorSetWPtr(this->m_vec, &w);
	}



	///
	scalar float4::getx() const 
	{
		return float4::unwrapx(this->m_vec);
	}


	///
	scalar float4::gety() const 
	{
		return float4::unwrapy(this->m_vec);
	}


	///
	scalar float4::getz() const 
	{
		return float4::unwrapz(this->m_vec);
	}


	///
	scalar float4::getw() const 
	{
		return float4::unwrapw(this->m_vec);
	}


	///
	scalar & float4::getx()
	{
		return this->m_vec.m128_f32[0];
	}


	///
	scalar & float4::gety()
	{
		return this->m_vec.m128_f32[1];
	}


	///
	scalar & float4::getz()
	{
		return this->m_vec.m128_f32[2];
	}


	///
	scalar & float4::getw()
	{
		return this->m_vec.m128_f32[3];
	}





	///
	scalar float4::length() const 
	{
		return float4::unwrapx(XMVector4Length(this->m_vec));
	}


	///
	scalar float4::lengthsq() const 
	{
		return float4::unwrapx(XMVector4LengthSq(this->m_vec));
	}


	///
	float4 float4::abs() const 
	{
		return XMVectorAbs(this->m_vec);
	}





	///
	float4 float4::reciprocal(const Math::float4 &f)
	{
		return XMVectorReciprocal(f.m_vec);
	}


	///
	float4 float4::multiply(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMVectorMultiply(f1.m_vec, f2.m_vec);
	}


	///
	float4 float4::cross3(const float4 & f1, const float4 & f2)
	{
		return XMVector3Cross(f1.m_vec, f2.m_vec);
	}


	///
	scalar float4::dot3(const float4 & f1, const float4 & f2)
	{
		return float4::unwrapx(XMVector3Dot(f1.m_vec, f2.m_vec));
	}


	///
	float4 float4::normalize(const float4 & f)
	{
		return XMVector3Normalize(f.m_vec);
	}


	///
	float4 float4::maximize(const float4 & f1, const float4 & f2)
	{
		return XMVectorMax(f1.m_vec, f2.m_vec);
	}


	///
	float4 float4::minimize(const float4 & f1, const float4 & f2)
	{
		return XMVectorMin(f1.m_vec, f2.m_vec);
	}


	///
	float4 float4::barycentric(const Math::float4 &f1, const Math::float4 &f2, const Math::float4 &f3, scalar f, scalar g)
	{
		return XMVectorBaryCentric(f1.m_vec, f2.m_vec, f3.m_vec, f, g);
	}


	///
	float4 float4::catmullrom(const Math::float4 &f1, const Math::float4 &f2, const Math::float4 &f3, const Math::float4 &f4, scalar s)
	{
		return XMVectorCatmullRom(f1.m_vec, f2.m_vec, f3.m_vec, f4.m_vec, s);
	}


	///
	float4 float4::hermite(const Math::float4 &f1, const Math::float4 &t1, const Math::float4 &f2, const Math::float4 &t2, scalar s)
	{
		return XMVectorHermite(f1.m_vec, t1.m_vec, f2.m_vec, t2.m_vec, s);
	}


	///
	float4 float4::clamp(const Math::float4 &clamp, const Math::float4 &min, const Math::float4 &max)
	{
		return XMVectorClamp(clamp.m_vec, min.m_vec, max.m_vec);
	}


	///
	float4 float4::reflect(const Math::float4 &n, const Math::float4 &i)
	{
		return XMVector3Reflect(n.m_vec, i.m_vec);
	}


	///
	scalar float4::angle(const Math::float4 &f1, const Math::float4 &f2)
	{
		return float4::unwrapx(XMVector4AngleBetweenVectors(f1.m_vec, f2.m_vec));
	}


	///
	float4 float4::lerp(const Math::float4 &f1, const float4 &f2, scalar s)
	{
		return XMVectorLerp(f1.m_vec, f2.m_vec, s);
	}


	float4 float4::transform(const Math::float4 &f, const Math::matrix &m)
	{
		return XMVector4Transform(f.m_vec, m.m_matrix);
	}





	///
	bool float4::l3_all(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAllFalse(XMVector3GreaterR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::l3_any(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAnyFalse(XMVector3GreaterR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::l4_all(const Math::float4 & f1, const Math::float4 & f2)
	{
		return XMComparisonAllFalse(XMVector4GreaterR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::l4_any(const Math::float4 & f1, const Math::float4 & f2)
	{
		return XMComparisonAnyFalse(XMVector4Less(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::le3_all(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAllFalse(XMVector3GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::le3_any(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAnyFalse(XMVector3GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::le4_all(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAllFalse(XMVector4GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::le4_any(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAnyFalse(XMVector4GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::g3_all(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAllTrue(XMVector3GreaterR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::g3_any(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAnyTrue(XMVector3GreaterR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::g4_all(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAllTrue(XMVector4GreaterR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::g4_any(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAnyTrue(XMVector4GreaterR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::ge3_all(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAllTrue(XMVector3GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::ge3_any(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAnyTrue(XMVector3GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::ge4_all(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAllTrue(XMVector4GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::ge4_any(const Math::float4 &f1, const Math::float4 &f2)
	{
		return XMComparisonAnyTrue(XMVector4GreaterOrEqualR(f1.m_vec, f2.m_vec));
	}


	///
	bool float4::ne3(const Math::float4 &f1, const Math::float4 &f2, const Math::float4 &epsilon)
	{
		return (0 != XMVector3NearEqual(f1.m_vec, f2.m_vec, epsilon.m_vec));
	}


	///
	bool float4::ne4(const Math::float4 &f1, const Math::float4 &f2, const Math::float4 &epsilon)
	{
		return (0 != XMVector4NearEqual(f1.m_vec, f2.m_vec, epsilon.m_vec));
	}





	///
	scalar float4::unwrapx(XMVECTOR v)
	{
		scalar result;

		XMVectorGetXPtr(&result, v);

		return result;
	}


	///
	scalar float4::unwrapy(XMVECTOR v)
	{
		scalar result;

		XMVectorGetYPtr(&result, v);

		return result;
	}


	///
	scalar float4::unwrapz(XMVECTOR v)
	{
		scalar result;

		XMVectorGetZPtr(&result, v);

		return result;
	}


	///
	scalar float4::unwrapw(XMVECTOR v)
	{
		scalar result;

		XMVectorGetWPtr(&result, v);

		return result;
	}


	///
	float4 float4::wrap(scalar s)
	{
		XMVECTOR temp; 
		temp = XMVectorSetX(temp, s);

		return (float4)XMVectorSplatX(temp);
	}


	///
	float4 float4::wrapx(const float4 & f)
	{
		return (float4)XMVectorSplatX(f.m_vec);
	}


	///
	float4 float4::wrapy(const float4 & f)
	{
		return (float4)XMVectorSplatY(f.m_vec);
	}


	///
	float4 float4::wrapz(const float4 & f)
	{
		return (float4)XMVectorSplatZ(f.m_vec);
	}


	///
	float4 float4::wrapw(const float4 & f)
	{
		return (float4)XMVectorSplatW(f.m_vec);
	}
}

#endif // RE_USE_DX